/* -*- c++ -*- */
/*
 * Copyright 2023 luxian.
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#include <gnuradio/io_signature.h>
#include "my_qpsk_demod_cb_impl.h"

namespace gr {
  namespace customModule {


    using input_type =gr_complex;

    using output_type =gr_complex;
    my_qpsk_demod_cb::sptr
    my_qpsk_demod_cb::make(bool d_gray_code)
    {
      return gnuradio::make_block_sptr<my_qpsk_demod_cb_impl>(
        d_gray_code);
    }


    /*
     * The private constructor
     */
    my_qpsk_demod_cb_impl::my_qpsk_demod_cb_impl(bool gray_code)
      : gr::sync_block("my_qpsk_demod_cb",
              gr::io_signature::make(1 /* min inputs */, 1 /* max inputs */, sizeof(input_type)),
              gr::io_signature::make(1 /* min outputs */, 1 /*max outputs */, sizeof(output_type)))
    {
      d_gray_code = gray_code;
    }

    /*
     * Our virtual destructor.
     */
    my_qpsk_demod_cb_impl::~my_qpsk_demod_cb_impl()
    {
    }

    int
    my_qpsk_demod_cb_impl::work(int noutput_items,
        gr_vector_const_void_star &input_items,
        gr_vector_void_star &output_items)
    {
      auto in = static_cast<const input_type*>(input_items[0]);
      auto out = static_cast<output_type*>(output_items[0]);

      for(int i = 0; i < noutput_items; i++)
      {
      out[i] = get_minimum_distances(in[i]);
      }
      // Tell runtime system how many input items we consumed on
      // each input stream.
      consume_each (noutput_items);

      // Tell runtime system how many output items we produced.

      // Tell runtime system how many output items we produced.
      return noutput_items;
    }
      
 unsigned char my_qpsk_demod_cb_impl::get_minimum_distances (const gr_complex &sample)
      {
    if (d_gray_code) {
          unsigned char bit0 = 0;
          unsigned char bit1 = 0;
          // The two left quadrants (quadrature component < 0) have this bit set to 1
          if (sample.real() < 0) {
            bit0 = 0x01;
          }
          // The two lower quadrants (in-phase component < 0) have this bit set to 1
          if (sample.imag()< 0) {
            bit1 = 0x01 << 1;
          }
          return bit0 | bit1;
    } 
  else {
      // For non-gray code, we can't simply decide on signs, so we check every single quadrant.
      if (sample.imag() >=0  and sample.real() >= 0) {
          return 0x00;
      }
    else if (sample.imag() >= 0 and sample.real() < 0) {
        return 0x01;
      }

    else if (sample.imag() < 0 and sample.real() < 0) {
        return 0x02;
      }
    else if (sample.imag() < 0 and sample.real() >= 0) {
        return 0x03;
      }
    }
  }
  } /* namespace customModule */
} /* namespace gr */
